# -*- coding: utf-8 -*-
"""
文件操作模块
"""

import os
import csv
import glob
import shutil
import datetime
import tempfile
import io
from pathlib import Path
try:
    from PyQt6.QtWidgets import QApplication
    QT_AVAILABLE = True
except ImportError:
    QT_AVAILABLE = False
from utils.logger import log
from utils.input_dialogs import input_box
from utils.constants import (
    CSV_ROW_TEMPLATE, EXIT_PWD, STATE_MAP, STATE_COLOR, WORK_STATES,
    ROLE_MAP, GRACE_SECS, MUTEX_NAME,CSV_HEADER
)

# 全局文件锁
_FILE_LOCKS = []# 钥匙盒：谁想放文件锁，自己丢进来
_LOCKED_FILES = {}

def init_file_operations(data_dir, user_id): #初始化文件操作- 设置 _log_dir 等全局路径
    global _data_dir, _user_id, _log_dir
    _data_dir = data_dir
    _user_id = user_id
    _log_dir = os.path.join(data_dir, 'logs')
    os.makedirs(_log_dir, exist_ok=True)

def flush_one_record(fname, uid, st, start_time, end_time, secs, date, 
                    task_id='', remark='', switch_type='手动',
                    project_name='', work_type='', workload1='', workload2=''):  # ★★★ 修改：添加 workload2 参数
    '''写一行 CSV（带文件锁/防占用重试）'''

    role = ROLE_MAP.get(uid[:2], '管理员')
    
    # 修改这里：作业状态统一记录为"作业"，非作业状态保持原样
    if st in WORK_STATES:
        display_state = '作业'  # 所有作业状态统一显示为"作业"
    else:
        display_state = STATE_MAP.get(st, st)  # 非作业状态保持原样
    
    work_flag = '作业' if st in WORK_STATES else '非作业'

    row = CSV_ROW_TEMPLATE.copy()
    
    # 填充数据
    row[0] = date  # 日期
    row[1] = uid  # 工号
    row[2] = role  # 角色
    row[3] = work_flag  # 作业/非作业
    row[4] = display_state  # 状态 - 使用修改后的显示状态
    row[5] = start_time.strftime('%H:%M:%S')  # 开始时间
    row[6] = end_time and end_time.strftime('%H:%M:%S') or ''  # 结束时间
    row[7] = str(secs)  # 时长(秒)
    row[8] = switch_type  # 主被动切换
    row[9] = project_name  # 项目名称
    row[10] = work_type  # 作业类型
    row[11] = task_id  # 任务ID
    row[12] = workload1  # 工作量1
    row[13] = workload2  # ★★★ 修改：工作量2
    # ★★★ 新增：自动计算工作量3 = 工作量1 / 工作量2
    try:
        if workload1 and workload2 and float(workload2) != 0:
            workload3 = float(workload1) / float(workload2)
            row[14] = f"{workload3:.1%}"  # 工作量3，百分比显示
        else:
            row[14] = ""  # 如果无法计算，留空
    except:
        row[14] = ""  # 如果计算出错，留空
    row[15] = remark  # 备注
    
    # 1) 如果还没锁，就独占打开
    if fname not in _LOCKED_FILES:
        try:
            fd = os.open(fname, os.O_RDWR | os.O_CREAT | os.O_BINARY)
            _LOCKED_FILES[fname] = fd
            _FILE_LOCKS.append(fd)
        except Exception as e:
            log(f'[WARN] 无法独占锁定 {fname}，继续写入：{e}')
    else:
        fd = _LOCKED_FILES[fname]
        # 检查文件描述符是否有效
        try:
            os.fstat(fd)  # 测试文件描述符是否有效
        except OSError:
            try:
                os.close(fd)
                fd = os.open(fname, os.O_RDWR | os.O_CREAT | os.O_BINARY)
                _LOCKED_FILES[fname] = fd
            except Exception as e:
                log(f'[ERR] 重新打开文件失败: {e}')
                fd = None

    # 2) 追加写
    try:
        if fd is not None:
            # 确保文件指针在末尾
            os.lseek(fd, 0, os.SEEK_END)
            current_pos = os.lseek(fd, 0, os.SEEK_CUR)
            
            # 如果是空文件，写入BOM和表头
            if current_pos == 0:
                os.write(fd, '\ufeff'.encode('utf-8-sig'))
                os.write(fd, (','.join(CSV_HEADER) + '\r\n').encode('utf-8'))
            
            line = io.StringIO()
            cw = csv.writer(line)
            cw.writerow(row)
            os.write(fd, line.getvalue().encode('utf-8'))
        else:
            # 备用方案：普通方式写入
            with open(fname, 'a', newline='', encoding='utf-8-sig') as f:
                cw = csv.writer(f)
                if f.tell() == 0:
                    cw.writerow(CSV_HEADER)
                cw.writerow(row)
            log(f'[SAVE] 通过备用方案写入记录: {STATE_MAP.get(st, st)}')

    except PermissionError:
        log(f'[WARN] 文件被占用，尝试创建备份文件: {fname}')
        base, ext = os.path.splitext(fname)
        counter = 1
        # 定义 new_fname
        new_fname = f"{base}_backup_{counter}{ext}"
        while os.path.exists(new_fname):
            counter += 1
            new_fname = f"{base}_backup_{counter}{ext}"
        
        # 在备份文件中写入数据
        try:
            with open(new_fname, 'w', newline='', encoding='utf-8-sig') as f:
                cw = csv.writer(f)
                cw.writerow(CSV_HEADER)
                cw.writerow(row)
            log(f'[WARN] 原文件被占用，已写入备份文件: {new_fname}')
        except Exception as backup_error:
            log(f'[ERR] 备份文件写入也失败: {backup_error}')

def view_records(): #查看记录
    """查看记录"""
    global _user_id, _log_dir
    
    try:
        today = datetime.datetime.now().strftime('%Y-%m-%d')
        today_file = os.path.join(_log_dir, f'{today}_{_user_id}.csv')
        
        if os.path.exists(today_file):
            os.startfile(today_file)
            log(f'[INFO] 已打开今日记录文件: {today_file}')
        else:
            os.startfile(_log_dir)
            log('[INFO] 今日无记录，已打开日志目录')
            
    except Exception as e:
        log(f'[ERR] 查看记录失败: {e}')

def view_all_records(): #查看所有记录
    """查看所有历史记录"""
    global _log_dir
    
    try:
        os.startfile(_log_dir)
        log('[INFO] 已打开日志目录')
    except Exception as e:
        log(f'[ERR] 打开日志目录失败: {e}')

def show_records_summary(): #显示今日统计
    global _user_id, _log_dir
    
    try:
        today = datetime.datetime.now().strftime('%Y-%m-%d')
        today_file = os.path.join(_log_dir, f'{today}_{_user_id}.csv')

        if not os.path.exists(today_file):
            return "今日暂无工作记录"

        work_states = ['DataWork', 'Rework']
        
        total_work_seconds = 0
        state_durations = {state: 0 for state in work_states}
        total_workload = 0
        
        with open(today_file, 'r', encoding='utf-8-sig') as f:
            reader = csv.reader(f)
            header = next(reader, None)
            
            for row in reader:
                if len(row) < 9:
                    continue
                    
                state = None
                state_display = row[4]
                for state_key, state_name in STATE_MAP.items():
                    if state_name == state_display:
                        state = state_key
                        break
                
                if state in work_states and row[8].isdigit():
                    duration = int(row[8])
                    total_work_seconds += duration
                    state_durations[state] += duration

        if total_work_seconds == 0:
            return "今日暂无工作投入记录"

        total_min = total_work_seconds // 60
        work_h, work_m = divmod(total_min, 60)

        state_details = []
        for state in work_states:
            if state_durations[state] > 0:
                state_min = state_durations[state] // 60
                state_h, state_m = divmod(state_min, 60)
                percentage = (state_durations[state] / total_work_seconds) * 100
                state_name = STATE_MAP.get(state, state)
                state_details.append(f"  - {state_name}: {state_h}小时{state_m}分钟 ({percentage:.1f}%)")


        state_details_text = "\n".join(state_details) if state_details else "  - 无详细分类数据"
        
        summary = (
            f"📊 今日工作投入统计\n\n"
            f"⏱️ 总工作时长：{work_h}小时{work_m}分钟\n"
            f"📦 累计框量：{total_workload:,}\n"
            f"📋 工作状态分布：\n{state_details_text}"
        )

        return summary

    except Exception as e:
        log(f'[ERR] 显示今日统计失败: {e}')
        return f"生成统计失败：{e}"

def update_last_row_end_time(csv_path, end_time):
    """占就跳过版：文件被占用直接放弃，30 秒后再补"""
    import os, errno

    # 1. 先判断文件是否能以“写”方式打开
    try:
        # 只测试，不真写，测完立刻关
        with open(csv_path, 'a', newline=''):
            pass
    except (OSError, IOError, PermissionError) as e:
        # 任何“写”不了的情况都跳过
        print(f"[SKIP] 文件被占用，跳过本次补填：{csv_path} 原因：{e}")
        return   # 直接回家，30 秒后又是一条好汉

    # 2. 能写就继续，按老逻辑走
    if csv_path in _LOCKED_FILES:
        fd = _LOCKED_FILES[csv_path]
        try:
            os.fstat(fd)          # 描述符还活着吗？
        except OSError:
            # 描述符坏了，清理记录
            try:
                os.close(fd)
            except:
                pass
            del _LOCKED_FILES[csv_path]

    # 3. 该用锁用锁，该无锁无锁
    if csv_path in _LOCKED_FILES:
        try:
            _update_with_file_lock(_LOCKED_FILES[csv_path], end_time)
            return
        except Exception as e:
            print(f"[WARN] 文件锁更新失败: {e}，改用无锁")
    _update_without_file_lock(csv_path, end_time)

def _update_with_file_lock(fd, end_time):
    """通过已锁定的文件描述符更新内容"""
    import io
    import csv
    try:
        os.fstat(fd)          # 简单测试描述符是否有效
    except OSError:
        print("[WARN] 文件描述符已损坏，改用无锁模式")
        # 退回到无锁方案
        fname = _LOCKED_FILES.inverse[fd]   # 通过 fd 反查文件名
        _update_without_file_lock(fname, end_time)
        return
    
    try:
        # 读取整个文件内容
        os.lseek(fd, 0, os.SEEK_SET)
        content_bytes = b''
        while True:
            chunk = os.read(fd, 4096)
            if not chunk:
                break
            content_bytes += chunk
        
        if not content_bytes:
            return
            
        content = content_bytes.decode('utf-8-sig')
        lines = content.splitlines()
        
        if len(lines) <= 1:  # 只有表头或空文件
            return
            
        # 解析最后一行（确保是有效的CSV行）
        last_line = lines[-1]
        
        # 检查最后一行是否包含多行数据（数据错位）
        if last_line.count(',') > len(CSV_HEADER):
            log(f'[WARN] 检测到数据错位，尝试修复最后一行')
            # 找到第一个完整的数据行结束位置
            parts = last_line.split(',')
            if len(parts) >= len(CSV_HEADER):
                # 取第一个完整的数据行
                last_line = ','.join(parts[:len(CSV_HEADER)])
                # 剩余部分作为新行（如果有）
                remaining = ','.join(parts[len(CSV_HEADER):])
                if remaining:
                    lines.append(remaining)
        
        reader = csv.reader([last_line])
        try:
            last_row = list(reader)[0]
        except Exception as e:
            log(f'[ERR] 解析最后一行失败: {e}')
            return
        
        if len(last_row) < 8:  # 确保有足够的列
            return
        
        # 更新结束时间和时长
        date_str = last_row[0]      # 日期
        start_str = last_row[5]     # 开始时间
        
        try:
            start_dt = datetime.datetime.strptime(f"{date_str} {start_str}", '%Y-%m-%d %H:%M:%S')
        except ValueError:
            try:
                start_dt = datetime.datetime.strptime(f"{date_str} {start_str}", '%Y/%m/%d %H:%M:%S')
            except ValueError:
                log(f'[ERR] 无法解析日期时间: {date_str} {start_str}')
                return
        
        last_row[6] = end_time.strftime('%H:%M:%S')  # 结束时间
        last_row[7] = str(int((end_time - start_dt).total_seconds()))  # 时长
        
        # 重新构建内容，确保每行都有正确的换行符
        lines[-1] = ','.join(last_row)
        new_content = '\r\n'.join(lines) + '\r\n'  # 确保最后有换行符
        
        # 清空文件并写入新内容
        os.ftruncate(fd, 0)
        os.lseek(fd, 0, os.SEEK_SET)
        os.write(fd, new_content.encode('utf-8-sig'))
        os.lseek(fd, 0, os.SEEK_END)  # 将指针移回文件末尾
        
    except Exception as e:
        log(f'[ERR] 文件锁更新失败: {e}')

def _update_without_file_lock(csv_path, end_time):
    """没有文件锁时的回退方案"""
    tmp_path = csv_path + '.tmp'
    try:
        with open(csv_path, 'r', newline='', encoding='utf-8-sig') as f_in, \
             open(tmp_path, 'w', newline='', encoding='utf-8-sig') as f_out:
            reader = csv.reader(f_in)
            rows = list(reader)
            if len(rows) <= 1:  # 只有表头
                return
            last = rows[-1]
            
            date_str = last[0]      # 日期
            start_str = last[5]     # 开始时间
            
            try:
                start_dt = datetime.datetime.strptime(f"{date_str} {start_str}", '%Y-%m-%d %H:%M:%S')
            except ValueError:
                try:
                    start_dt = datetime.datetime.strptime(f"{date_str} {start_str}", '%Y/%m/%d %H:%M:%S')
                except ValueError:
                    log(f'[ERR] 无法解析日期时间: {date_str} {start_str}')
                    return

            last[6] = end_time.strftime('%H:%M:%S')  # 结束时间
            last[7] = str(int((end_time - start_dt).total_seconds()))  # 时长

            csv.writer(f_out).writerows(rows)
        shutil.move(tmp_path, csv_path)
    except Exception as e:
        log(f'[ERR] 无锁更新失败: {e}')
        try:
            os.remove(tmp_path)
        except:
            pass
def _get_last_row_workload():
    """获取当前最后一行的工作量1字段内容"""
    global _user_id, _log_dir
    
    try:
        today = datetime.datetime.now().strftime('%Y-%m-%d')
        today_file = os.path.join(_log_dir, f'{today}_{_user_id}.csv')
        
        if not os.path.exists(today_file):
            return ""  # 文件不存在，返回空
            
        # 读取最后一行
        with open(today_file, 'r', encoding='utf-8-sig') as f:
            lines = f.readlines()
            if len(lines) <= 1:  # 只有表头
                return ""
            
            last_line = lines[-1]
            # 解析CSV行
            import csv
            from io import StringIO
            reader = csv.reader(StringIO(last_line))
            last_row = list(reader)[0]
            
            # 工作量1在第13列（索引12）
            if len(last_row) > 12:
                return last_row[12].strip()
            else:
                return ""
                
    except Exception as e:
        log(f'[ERR] 获取最后一行工作量失败: {e}')
        return ""

def _update_current_row_workload(workload):
    """更新当前最后一行的工作量1字段"""
    global _user_id, _log_dir
    
    try:
        today = datetime.datetime.now().strftime('%Y-%m-%d')
        today_file = os.path.join(_log_dir, f'{today}_{_user_id}.csv')
        
        if not os.path.exists(today_file):
            return False
            
        # 读取所有行
        with open(today_file, 'r', encoding='utf-8-sig') as f:
            lines = f.readlines()
            if len(lines) <= 1:  # 只有表头
                return False
            
            # 解析最后一行
            import csv
            from io import StringIO
            reader = csv.reader(StringIO(lines[-1]))
            last_row = list(reader)[0]
            
            # 更新工作量1字段（第13列，索引12）
            if len(last_row) > 12:
                last_row[12] = workload
            else:
                # 如果列数不够，补齐到13列
                while len(last_row) < 13:
                    last_row.append('')
                last_row[12] = workload
            
            # 重新写入文件
            with open(today_file, 'w', encoding='utf-8-sig') as f:
                # 写入表头和其他行
                for i in range(len(lines) - 1):
                    f.write(lines[i])
                
                # 写入更新后的最后一行
                writer = csv.writer(f)
                writer.writerow(last_row)
                
            log(f'[WORKLOAD] 已更新当前行工作量: {workload}')
            return True
            
    except Exception as e:
        log(f'[ERR] 更新当前行工作量失败: {e}')
        return False

def register_close_segment_callback(func):
    global _close_prev_segment_cb
    _close_prev_segment_cb = func

def _close_previous_segment_proxy(end_time):
    if _close_prev_segment_cb:
        _close_prev_segment_cb(end_time)

def release_all_locks(): #关掉之前登记的锁
    """把自己以前登记的锁全部关掉"""
    global _FILE_LOCKS
    for fd in _FILE_LOCKS:
        try:
            os.close(fd)
        except Exception:
            pass
    _FILE_LOCKS.clear()

def _update_current_row_workload(workload):
    """只改今天最后一行的工作量1字段，成功返回 True，没文件返回 False"""
    global _user_id, _log_dir
    import csv
    from datetime import datetime

    today = datetime.now().strftime('%Y-%m-%d')
    today_file = os.path.join(_log_dir, f'{today}_{_user_id}.csv')

    if not os.path.exists(today_file):
        return False

    # 读全部行
    with open(today_file, 'r', encoding='utf-8-sig', newline='') as f:
        reader = list(csv.reader(f))
    if len(reader) <= 1:          # 只有表头
        return False

    # 改最后一行
    last_row = reader[-1]
    if len(last_row) > 12:        # 保证有工作量1 这一列
        last_row[12] = workload
    else:
        # 列数不够就补到 13 列
        while len(last_row) < 13:
            last_row.append('')
        last_row[12] = workload

    # 写回文件
    with open(today_file, 'w', encoding='utf-8-sig', newline='') as f:
        writer = csv.writer(f)
        writer.writerows(reader)

    return True